/**
 * Author(s): xuming.Wong <xuming.Wong@gmail.com>
 */
#include "EntityComponent.h"

#include "GameObject.h"
#include "SceneObject.h"

namespace PQEngine
{
	EntityComponent* EntityComponent::get(int id)
	{
		Object* obj=Object::getObject(id);
		if(obj==NULL){
			return NULL;
		}
		ObjectType objectType=obj->getObjectType();
		if(objectType==OBJECT_TYPE_COMPONENT_ENTITY){
			return (EntityComponent*)obj;
		}else{
			return NULL;
		}
	}


	EntityComponent::EntityComponent(Ogre::Entity* entity)
		: Component(OBJECT_TYPE_COMPONENT_ENTITY),_entity(entity),
		_highLighted(false),_animEnabled(false),_animIndex(0)
	{
		initAnimations();
		initSubEntities();
	}

	int EntityComponent::getNumSubMesh()
	{
		if(_entity){
			Ogre::MeshPtr meshPtr=_entity->getMesh();
			
			return meshPtr->getNumSubMeshes();
		}
		return 0;
		
	}

	std::string EntityComponent::getSubMeshMaterialName(unsigned short index)
	{
		if(_entity){
			Ogre::MeshPtr meshPtr=_entity->getMesh();
			Ogre::SubMesh *submesh=meshPtr->getSubMesh(index);
			return submesh->getMaterialName();
		}

		return "";	
	}

	EntityComponent::~EntityComponent()
	{
		if(_entity){
			SceneObject::getActive()->getSceneManager()->destroyEntity(_entity);
		}
	}
	
	void EntityComponent::setAnimState(bool state)
	{
		int size=_animationStates.size();
		for (int i = 0; i <size ; i++){
			_animationStates[i]->setEnabled(false);
			
		}

		_animEnabled=state;
		_animationStates[_animIndex]->setEnabled(state);
	}


	void EntityComponent::initAnimations()
	{
		if(_entity==NULL){
			return;
		}

		Ogre::AnimationStateSet *anims=_entity->getAllAnimationStates();
		if(!anims){
			return;
		}

		Ogre::AnimationStateIterator iter=anims->getAnimationStateIterator();
		while(iter.hasMoreElements()){
			Ogre::AnimationStateMap::mapped_type i=iter.getNext();
			_animationNames.push_back(i->getAnimationName());
		}

		Ogre::SkeletonInstance* skeleton = _entity->getSkeleton();
		if(skeleton){
			skeleton->setBlendMode(Ogre::ANIMBLEND_CUMULATIVE);
		}

		int size=_animationNames.size();
		_animationStates.resize(size);
		for (int i = 0; i <size ; i++){
			_animationStates[i] = _entity->getAnimationState(_animationNames[i]);
			_animationStates[i]->setLoop(true);
		}
	}

	

	//manager mesh animations and...
	void EntityComponent::update(float deltaT)
	{
		if(_animEnabled){
			
			_animationStates[_animIndex]->addTime(deltaT);
		}
	}

	void EntityComponent::setMaterialName(std::string materialName)
	{
		if(_entity){
			_entity->setMaterialName(materialName);
		}
	}

	float EntityComponent::getRadius()
	{
		if(_entity){
			float radius=_entity->getBoundingRadius();	
			return radius;
		}else{
			return 0;
		}
	}

	Ogre::Vector3 EntityComponent::getBoundingBoxSize(void) const
	{
		if(_entity){
			Ogre::AxisAlignedBox box=_entity->getBoundingBox();
			Ogre::Vector3 size=box.getSize();
			return size;
		}else{
			return Ogre::Vector3(0,0,0);
		}
	}

	Ogre::AxisAlignedBox EntityComponent::getBoundingBox(void) const
	{
		if(_entity){			
			Ogre::AxisAlignedBox box=_entity->getBoundingBox();			
			return box;
		}else{
			return Ogre::AxisAlignedBox::BOX_NULL;
		}
	}


	Ogre::AxisAlignedBox EntityComponent::getWorldBoundingBox(void) const
	{
		if(_entity){
			Ogre::AxisAlignedBox box=_entity->getWorldBoundingBox();
			return box;
		}else{
			return Ogre::AxisAlignedBox::BOX_NULL;
		}
	}

	void EntityComponent::initSubEntities()
	{
		assert(_entity);
		int cnt=_entity->getNumSubEntities();

		//init normal material
		for(int i=0;i<cnt;i++){
			Ogre::SubEntity *entity=_entity->getSubEntity(i);
			Ogre::MaterialPtr mat=entity->getMaterial();
			_materials[ENTITY_MATERIAL_NORMAL].push_back(mat);
		}

		//create highlight material
		for(int i=0;i<cnt;i++){
			Ogre::String name=_materials[ENTITY_MATERIAL_NORMAL][i]->getName()+"/HighLighted";
			Ogre::MaterialPtr mat= _materials[ENTITY_MATERIAL_NORMAL][i]->clone(name);
			int techcnt=mat->getNumTechniques();
			for(int j=0;j<techcnt;j++){
				Ogre::Technique* tech=mat->getTechnique(j);
				Ogre::Pass* pass=tech->createPass();
				
				pass->setPolygonMode(Ogre::PM_WIREFRAME);
				pass->setNormaliseNormals(true);
				pass->setSceneBlendingOperation(Ogre::SBO_MAX);
				pass->setSelfIllumination(Ogre::ColourValue(1.0f,1.0f,1.0f));
				
			}
			_materials[ENTITY_MATERIAL_HIGHLIGHT].push_back(mat);

		}


	}

	void EntityComponent::setNormalMaterial()
	{
		assert(_entity);
		int cnt=_entity->getNumSubEntities();
		for(int i=0;i<cnt;i++){
			Ogre::SubEntity *ent=_entity->getSubEntity(i);
			ent->setMaterial(_materials[ENTITY_MATERIAL_NORMAL][i]);
			
		}
	}

	void EntityComponent::highLight(bool lighted)
	{
		if(_highLighted==lighted){
			return;
		}

		int cnt=_entity->getNumSubEntities();
		for(int i=0;i<cnt;i++){
			if(lighted){
				Ogre::SubEntity *ent=_entity->getSubEntity(i);
				ent->setMaterial(_materials[ENTITY_MATERIAL_HIGHLIGHT][i]);
			}else{
				Ogre::SubEntity *ent=_entity->getSubEntity(i);
				ent->setMaterial(_materials[ENTITY_MATERIAL_NORMAL][i]);
			}
		}
		

		_highLighted=lighted;
	}

}
